package com.ikangtai.shecare.curve.mpchart;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import com.github.mikephil.charting.listener.ChartTouchListener;
import com.github.mikephil.charting.listener.OnChartGestureListener;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.ikangtai.shecare.R;
import com.ikangtai.shecare.common.App;
import com.ikangtai.shecare.common.al.DayUnitDSOutput;
import com.ikangtai.shecare.common.util.AppLog;
import com.ikangtai.shecare.record.bean.UserTemperatureInfo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BBTLineChart extends LineChart implements OnChartGestureListener, OnChartValueSelectedListener {

    private Context context;
    private BBTLineChartRenderer bbtLineChartRenderer;
    private ArrayList<ILineDataSet> lineDataSetList = new ArrayList<>();
    public static Map<Float, Float> bbtLineChartxValue2yValue = new HashMap<>();
    public static Map<Float, Float> bbtLineChartFullFillxValue2yValue = new HashMap<>();
    public static Map<Float, String> bbtLineChartxValue2PeriodMap = new HashMap<>();

    /**
     * X 相关
     */
    public static final float MIN_XAXIS_DAY = 0;
    public static final float MAX_XAXIS_DAY = 400;
    public static final float XAXIS_TODAY = MAX_XAXIS_DAY - 5; // 设置今天后留出5天
    private static final int XAXIS_LABEL_COUNT = 35;
    public static final float LEFT_EDGE_XAXIS_DAY = MAX_XAXIS_DAY - XAXIS_LABEL_COUNT; // 设置默认显示在Chart X左边缘位置的数字

    private static float NEED_FILL_XAXIS_DAY_START;
    private static float NEED_FILL_XAXIS_DAY_END;

    /**
     * Y 相关
     */
    public static final float MIN_YAXIS_BBT = 35.5f;
    public static final float MAX_YAXIS_BBT = 37.5f;
    private static final int YAXIS_LABEL_COUNT = 20;

    public static final float AXIS_TEXT_SIZE = 9f;
    public static final float LEGEND_TEXT_SIZE = 9f;

    /**
     * 颜色相关
     */
    public static final int MENSES_COLOR = Color.rgb(252, 136, 174);
    public static final int OVULATION_COLOR = Color.rgb(87, 187, 38);
    public static final int OVULATION_DAY_COLOR = Color.rgb(255, 201, 77);
    public static final int OTHER_PERIOD_COLOR = Color.rgb(14, 161, 247);
    public static final int TEXT_COLOR = Color.rgb(82, 79, 79);

//    public static final int SAFE_PERIOD_COLOR = Color.rgb(35, 192, 149);
//    public static final int DANGER_PERIOD_COLOR = Color.rgb(235, 54, 64);
    public static final int SAFE_PERIOD_COLOR = OTHER_PERIOD_COLOR;
    public static final int DANGER_PERIOD_COLOR = OVULATION_COLOR;

    public static final int HIGHLIGHT_LINE_COLOR = Color.rgb(14, 161, 247);



    private List<UserTemperatureInfo> BBTList;
    private float todayBBT;


    public BBTLineChart(Context context) {
        super(context);
    }

    public BBTLineChart(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BBTLineChart(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    public void init(Context context){
        this.context = context;
        initBBTXAxis();
        initBBTYAxis();

        initBBTChart();
    }

    private void initBBTXAxis(){
        XAxis xAxis = this.getXAxis();
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);//default is top
        xAxis.setAxisMinValue(MIN_XAXIS_DAY);
        xAxis.setAxisMaxValue(MAX_XAXIS_DAY);
        xAxis.setLabelCount(XAXIS_LABEL_COUNT);
        xAxis.setTextSize(AXIS_TEXT_SIZE);
        xAxis.setTextColor(TEXT_COLOR);
        xAxis.setTypeface(Typeface.create("Regular", Typeface.NORMAL));

        xAxis.setValueFormatter(new BBTXAxisValueFormatter());
    }

    private void initBBTYAxis(){
        YAxis leftAxis = this.getAxisLeft();
        setBBTYAxisBase(leftAxis);
        leftAxis.setValueFormatter(new BBTYAxisLeftValueFormatter());

        YAxis rightAxis = this.getAxisRight();
        rightAxis.setDrawAxisLine(true);
        rightAxis.setDrawLabels(true);
        setBBTYAxisBase(rightAxis);
        rightAxis.setValueFormatter(new BBTYAxisRightValueFormatter());
    }

    private void setBBTYAxisBase(YAxis yAxis){
        yAxis.setAxisMinValue(MIN_YAXIS_BBT);
        yAxis.setAxisMaxValue(MAX_YAXIS_BBT);
        yAxis.setLabelCount(YAXIS_LABEL_COUNT);
        yAxis.setTextSize(AXIS_TEXT_SIZE);
        yAxis.setTextColor(TEXT_COLOR);
    }

    private void initBBTChart(){
        getAxisRight().setEnabled(true);
        setNoDataTextDescription("没有数据, 请提供数据!");

        setScaleEnabled(false);
        setOnChartGestureListener(this);
        setOnChartValueSelectedListener(this);

        initBBTLegend();

        BBTMarkView bbtMarkView = new BBTMarkView(context, R.layout.bbtlinechart_markview);
        bbtMarkView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                AppLog.i("BBTMarkView onClick, e.getX() = " + BBTMarkView.selectedXAxisValue);
                Toast.makeText(context, "BBTMarkView e.getX() = " + BBTMarkView.selectedXAxisValue, Toast.LENGTH_LONG).show();
            }
        });
        setMarkerView(bbtMarkView);

        setDrawBorders(true);
        setBorderWidth(0.5f);
        setBorderColor(Color.LTGRAY);

        bbtLineChartRenderer = new BBTLineChartRenderer(this, getAnimator(), getViewPortHandler(), context);
        setRenderer(bbtLineChartRenderer);

        setVisibleXRangeMaximum(XAXIS_LABEL_COUNT);
        setVisibleYRangeMaximum(MAX_YAXIS_BBT, YAxis.AxisDependency.LEFT);
        setVisibleYRangeMaximum(MAX_YAXIS_BBT, YAxis.AxisDependency.RIGHT);
    }

    /**
     * legend 必须设置在X, Y之后才有效
     */
    public void initBBTLegend(){
        Legend legend = getLegend();
        //legend.setEnabled(false);
        // modify the legend ...
        legend.setPosition(Legend.LegendPosition.ABOVE_CHART_LEFT);
        legend.setForm(Legend.LegendForm.CIRCLE);

        if(App.status == 0){
            int [] colors = {MENSES_COLOR, OVULATION_COLOR, OVULATION_DAY_COLOR, OTHER_PERIOD_COLOR};
            String [] labels = {"月经期", "易孕期", "排卵日", "安全期"};
            legend.setCustom(colors, labels);
        }else{
            int [] colors = {MENSES_COLOR, DANGER_PERIOD_COLOR, OVULATION_DAY_COLOR, SAFE_PERIOD_COLOR, };
            String [] labels = {"月经期", "易孕期", "排卵日", "安全期"};
            legend.setCustom(colors, labels);
        }

        legend.setXOffset(0f);
        legend.setYOffset(2f);
        legend.setTextSize(LEGEND_TEXT_SIZE);
        legend.setTextColor(TEXT_COLOR);
    }

    public void setBBTData(){
        clearContainer();
        initBBTList();

        /**
         * 整体分为4步：
         * 1. 确定BBTList需要填充颜色的起始和末尾X值
         * 2. 确定不同状态下的不同周期阶段
         * 3. 获取BBTLineDataset
         * 4. 把1用不同的周期进行切割为不同的linedataset
         */
        if(BBTList.size() > 0) {
            initFilledStartEndXAxis();
            initPeriod();
            setBBTLineData();
            splitPeriod2LineDataSet();
        }
    }

    private void clearContainer(){
        lineDataSetList.clear();
        bbtLineChartxValue2yValue.clear();
        bbtLineChartxValue2PeriodMap.clear();
        bbtLineChartFullFillxValue2yValue.clear();
    }

    private void initBBTList(){
        long endTime = System.currentTimeMillis() / 1000;
        long startTime = (long) (endTime - (XAXIS_TODAY - MIN_XAXIS_DAY) * 24 * 3600);
        startTime = startTime - startTime % (24 * 3600);
        AppLog.i("BBTLineChart startTime = " + startTime + ", endTime = " + endTime);

        BBTList = UserTemperatureInfo.getBBTList(context, App.userName, startTime, endTime);
    }

    private void initFilledStartEndXAxis(){
        float firstTempXAxisValue = 0;

        for(int i = 0; i < BBTList.size(); i++){
            if(BBTList.get(i).isBBT()){
                firstTempXAxisValue = BBTLineUtil.getXAxisValue(BBTList.get(i).getMeasureTime());
                break;
            }
        }

        float firstDayOutputXAxisValue = BBTLineUtil.getDayoutputFirstX();
        NEED_FILL_XAXIS_DAY_START = Math.max(firstTempXAxisValue, firstDayOutputXAxisValue);
        NEED_FILL_XAXIS_DAY_START = Math.max(NEED_FILL_XAXIS_DAY_START, MIN_XAXIS_DAY);
        AppLog.i("BBTLineChart firstTempXAxisValue = " + firstTempXAxisValue + ", firstDayOutputXAxisValue = " + firstDayOutputXAxisValue + ", NEED_FILL_XAXIS_DAY_START = " + NEED_FILL_XAXIS_DAY_START);


        float finalTempXAxisValue = 0;
        for(int i = BBTList.size() - 1; i >= 0; i--){
            if(BBTList.get(i).isBBT()){
                finalTempXAxisValue = BBTLineUtil.getXAxisValue(BBTList.get(i).getMeasureTime());
                break;
            }
        }

        float finalDayOutputXAxisValue = BBTLineUtil.getDayoutputFinalX();
        NEED_FILL_XAXIS_DAY_END = Math.min(finalTempXAxisValue, finalDayOutputXAxisValue);
        NEED_FILL_XAXIS_DAY_END = Math.min(NEED_FILL_XAXIS_DAY_END, MAX_XAXIS_DAY);
        AppLog.i("BBTLineChart finalTempXAxisValue = " + finalTempXAxisValue + ", finalDayOutputXAxisValue = " + finalDayOutputXAxisValue + ", NEED_FILL_XAXIS_DAY_END = " + NEED_FILL_XAXIS_DAY_END);
    }

    private void initPeriod(){
        Menses.init();

        if (App.status == 0) {
            Ovulation.init(); //排卵期
        } else {
            SafePeriod.init();
            DangerPeriod.init();
        }
    }

    private void setBBTLineData(){
        int BBTListLen = BBTList.size();
        LineDataSet lineDataSet;
        List<Entry> EntryList = new ArrayList<>();

        List<Integer> circleColors = new ArrayList<>();
        List<Integer> lineColors = new ArrayList<>();

        for(int i = 0; i < BBTListLen; i++){
            UserTemperatureInfo userTemperatureInfo = BBTList.get(i);

            if(userTemperatureInfo.isBBT()){
                long measureTime = userTemperatureInfo.getMeasureTime();
                if(App.status == 0) {
                    if (Menses.isInMenses(measureTime)) {
                        circleColors.add(MENSES_COLOR); //粉色
                        lineColors.add(MENSES_COLOR); //粉色
                    } else if (Ovulation.isInOvulation(measureTime)) {

                        if (Ovulation.isOvulationDay(measureTime))
                            circleColors.add(OVULATION_DAY_COLOR); //橙色
                        else
                            circleColors.add(OVULATION_COLOR); //绿色

                        lineColors.add(OVULATION_COLOR); //绿色
                    } else {
                        circleColors.add(OTHER_PERIOD_COLOR); //蓝色
                        lineColors.add(OTHER_PERIOD_COLOR); //蓝色
                    }
                }else{
                    if (Menses.isInMenses(measureTime)) {
                        circleColors.add(MENSES_COLOR); //粉色
                        lineColors.add(MENSES_COLOR); //粉色
                    } else if (SafePeriod.isInSafePeriod(measureTime)) {
                        circleColors.add(SAFE_PERIOD_COLOR); //绿色
                        lineColors.add(SAFE_PERIOD_COLOR); //绿色
                    } else if (DangerPeriod.isInDangerPeriod(measureTime)) {
                        circleColors.add(DANGER_PERIOD_COLOR); //红色
                        lineColors.add(DANGER_PERIOD_COLOR); //红色
                    }else {
                        circleColors.add(OTHER_PERIOD_COLOR); //蓝色
                        lineColors.add(OTHER_PERIOD_COLOR); //蓝色
                    }
                }

                float x = BBTLineUtil.getXAxisValue(measureTime);
                float y = (float)(userTemperatureInfo.getTemperature());

                bbtLineChartxValue2yValue.put(x, y);
                EntryList.add(new Entry(x, y));
                AppLog.i("BBTLineChart x = " + x + ", y = " + y);

                todayBBT = 0;
                if(x == XAXIS_TODAY)
                    todayBBT = y;
            }
        }

        lineDataSet = new LineDataSet(EntryList, "shecare");

        BBTLineUtil.setLineStyle(lineDataSet);
        lineDataSet.setColors(lineColors); //线条的颜色
        lineDataSet.setCircleColors(circleColors); //圆圈的颜色

        lineDataSet.setDrawHorizontalHighlightIndicator(false);
        lineDataSet.setHighLightColor(HIGHLIGHT_LINE_COLOR);
        lineDataSet.setHighlightLineWidth(2f);

        lineDataSetList.add(lineDataSet);
    }

    private void splitPeriod2LineDataSet(){
        initBBTLineChartFullFillxValue2yValue();
        splitBBTLineChartFullFillIntoAreas();
    }

    private void initBBTLineChartFullFillxValue2yValue(){
        for(float i = NEED_FILL_XAXIS_DAY_START; i <= NEED_FILL_XAXIS_DAY_END; i++){
            Float y = bbtLineChartxValue2yValue.get(i);

            if(y != null) {
                bbtLineChartFullFillxValue2yValue.put(i, y);
                AppLog.i("BBTLineChart x has y value, no need filled! x = " + i + ", y = " + y);
            }else{
                y = BBTLineUtil.getFullfilledYValue(i);
                AppLog.i("BBTLineChart x has no y value, need filled! x = " + i + ", filled value bbtLineChartxValue2yValue.get(i) = " + y);
                bbtLineChartFullFillxValue2yValue.put(i, y);
            }
        }
    }

    private void splitBBTLineChartFullFillIntoAreas(){
        for(float i = NEED_FILL_XAXIS_DAY_START; i <= NEED_FILL_XAXIS_DAY_END; i++){
            List<Entry> EntryList = new ArrayList<>();
            String periodI = bbtLineChartxValue2PeriodMap.get(i);

            //安全期的填充往前多占用一格
            if(i != NEED_FILL_XAXIS_DAY_START && isBBTLineChartAQQ(periodI))
                EntryList.add(new Entry(i-1, bbtLineChartFullFillxValue2yValue.get(i-1)));

            EntryList.add(new Entry(i, bbtLineChartFullFillxValue2yValue.get(i)));
            AppLog.i("BBTLineChart i = " + i + ", periodI = " + periodI);

            if(i == NEED_FILL_XAXIS_DAY_END){
                LineDataSet lineDataSet = new LineDataSet(EntryList, null);
                BBTLineUtil.setFullFillLineStyle(lineDataSet, getDrawable(periodI));
                lineDataSetList.add(lineDataSet);
            }


            for(float j = i + 1; j <= NEED_FILL_XAXIS_DAY_END; j++){
                String periodJ = bbtLineChartxValue2PeriodMap.get(j);
                AppLog.i("BBTLineChart j = " + j + ", periodJ = " + periodJ);
                if(periodJ == periodI) //注意period == null的情况(即为htq/lpq)，所以这里不能用equals
                    EntryList.add(new Entry(j, bbtLineChartFullFillxValue2yValue.get(j)));
                else{
                    //安全期的填充往后多占用一格
                    if(i != NEED_FILL_XAXIS_DAY_END && isBBTLineChartAQQ(periodI))
                        EntryList.add(new Entry(j, bbtLineChartFullFillxValue2yValue.get(j)));

                    LineDataSet lineDataSet = new LineDataSet(EntryList, null);
                    BBTLineUtil.setFullFillLineStyle(lineDataSet, getDrawable(periodI));
                    lineDataSetList.add(lineDataSet);

                    i = j - 1; // 因为break之后要执行i++，故在这里-1抵消一个
                    break;
                }

                if(j == NEED_FILL_XAXIS_DAY_END){
                    LineDataSet lineDataSet = new LineDataSet(EntryList, null);
                    BBTLineUtil.setFullFillLineStyle(lineDataSet, getDrawable(periodI));
                    lineDataSetList.add(lineDataSet);
                    i = j;
                }
            }
        }
    }

    // period == null 表示备孕里的 HTQ & LPQ
    // period == DayUnitDSOutput.PERIOD_AQQ 表示避孕里的 AQQ
    // 上2种情况都属于BBTLineChart里的安全期
    private boolean isBBTLineChartAQQ(String period){
        return (period == null || period == DayUnitDSOutput.PERIOD_AQQ);
    }

    //注意period == null的情况(即为htq/lpq)，所以这里不能用equals
    private Drawable getDrawable(String period){
        Drawable drawable = getResources().getDrawable(R.drawable.fade_other);

        if(period == DayUnitDSOutput.PERIOD_YJQ)
            drawable = getResources().getDrawable(R.drawable.fade_menses);
        else if(period == DayUnitDSOutput.PERIOD_PLQ)
            drawable = getResources().getDrawable(R.drawable.fade_ovulation);
        else if(period == DayUnitDSOutput.PERIOD_AQQ)
            drawable = getResources().getDrawable(R.drawable.fade_safe);
        else if(period == DayUnitDSOutput.PERIOD_WXQ)
            drawable = getResources().getDrawable(R.drawable.fade_ovulation);

        return drawable;
    }

    /**
     * 综合画图部分
     */
    public void drawBBTChart(){
        // create a data object with the datasets
        LineData data = new LineData(lineDataSetList);

        // set data
        setData(data);
        setDescription("今日体温: " + getTodayBBT());
    }

    private String getTodayBBT(){
        return todayBBT == 0 ? "未测量" : todayBBT + " ºC";

    }

    @Override
    public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
        Log.i("Gesture", "START, x: " + me.getX() + ", y: " + me.getY());
    }

    @Override
    public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
        Log.i("Gesture", "END, lastGesture: " + lastPerformedGesture);

        // un-highlight values after the gesture is finished and no single-tap
        if(lastPerformedGesture != ChartTouchListener.ChartGesture.SINGLE_TAP)
            highlightValues(null); // or highlightTouch(null) for callback to onNothingSelected(...)
    }

    @Override
    public void onChartLongPressed(MotionEvent me) {
        Log.i("LongPress", "Chart longpressed.");
    }

    @Override
    public void onChartDoubleTapped(MotionEvent me) {
        Log.i("DoubleTap", "Chart double-tapped.");
    }

    @Override
    public void onChartSingleTapped(MotionEvent me) {
        Log.i("SingleTap", "Chart single-tapped.");
    }

    @Override
    public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {
        Log.i("Fling", "Chart flinged. this.getLowestVisibleX(): " + this.getLowestVisibleX() + ", this.getHighestVisibleX(): " + this.getHighestVisibleX());
    }

    @Override
    public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
        Log.i("Scale / Zoom", "ScaleX: " + scaleX + ", ScaleY: " + scaleY);
    }

    @Override
    public void onChartTranslate(MotionEvent me, float dX, float dY) {
        Log.i("Translate / Move", "dX: " + dX + ", dY: " + dY);
        Log.i("Translate / Move", "Chart Translate. this.getLowestVisibleX(): " + this.getLowestVisibleX() + ", this.getHighestVisibleX(): " + this.getHighestVisibleX());

    }

    @Override
    public void onValueSelected(Entry e, Highlight h) {
        //Toast.makeText(this.context, "x = " + e.getX() + ", y = " + e.getY(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onNothingSelected() {
    }


}
